# -*- coding: utf-8 -*-
# backend/api/file_routes.py
# backend/api/file_routes.py
"""
文件API路由 📄

处理项目文件的CRUD操作
"""

from fastapi import APIRouter, Depends, HTTPException, status, UploadFile, File as FastAPIFile
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy import select, func
from typing import List, Optional
import hashlib
import os
from pathlib import Path

from backend.database.connection import get_db
from backend.models.user import User
from backend.models.file import File
from backend.models.project import CollaboratorRole
from backend.api.auth_routes import require_auth
from backend.api.project_routes import check_project_access
from backend.utils.logger import get_logger
from backend.utils.security import sanitize_filename, validate_file_type
from backend.utils.log_utils import log_business_event
from backend.schemas.file import (
    FileResponse, FileCreateRequest, FileUpdateRequest,
    FileListResponse, FileUploadResponse
)

router = APIRouter()
logger = get_logger(__name__)

# 允许的文件扩展名
ALLOWED_EXTENSIONS = {
    '.py', '.js', '.ts', '.jsx', '.tsx', '.html', '.css', '.scss', '.less',
    '.rs', '.go', '.java', '.cpp', '.c', '.h', '.hpp', '.cs', '.php',
    '.rb', '.swift', '.kt', '.scala', '.clj', '.elm', '.hs', '.ml',
    '.json', '.yaml', '.yml', '.toml', '.ini', '.cfg', '.xml',
    '.md', '.txt', '.rst', '.log', '.env', '.gitignore', '.dockerfile'
}

# 最大文件大小 (5MB)
MAX_FILE_SIZE = 5 * 1024 * 1024


def calculate_file_checksum(content: str) -> str:
    """计算文件内容的SHA256校验和"""
    return hashlib.sha256(content.encode('utf-8')).hexdigest()


def count_lines(content: str) -> int:
    """计算文件行数"""
    return len(content.splitlines()) if content else 0


@router.get("/{project_id}/files", response_model=FileListResponse)
async def get_project_files(
        project_id: str,
        path: Optional[str] = None,
        file_type: Optional[str] = None,
        current_user: User = Depends(require_auth),
        db: AsyncSession = Depends(get_db)
):
    """获取项目文件列表 📋"""

    await check_project_access(project_id, current_user, db)

    # 构建查询条件
    filters = [File.project_id == project_id]

    if path:
        filters.append(File.path.startswith(path))

    if file_type:
        filters.append(File.file_type == file_type)

    # 查询文件
    result = await db.execute(
        select(File)
        .where(*filters)
        .order_by(File.path, File.name)
    )
    files = result.scalars().all()

    return FileListResponse(
        items=[FileResponse.from_orm(file) for file in files],
        total=len(files)
    )


@router.get("/{project_id}/files/{file_id}", response_model=FileResponse)
async def get_file(
        project_id: str,
        file_id: str,
        include_content: bool = True,
        current_user: User = Depends(require_auth),
        db: AsyncSession = Depends(get_db)
):
    """获取文件详情 📖"""

    await check_project_access(project_id, current_user, db)

    result = await db.execute(
        select(File).where(
            File.id == file_id,
            File.project_id == project_id
        )
    )
    file = result.scalar_one_or_none()

    if not file:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="文件不存在"
        )

    # 更新最后访问时间
    file.last_accessed_at = func.now()
    await db.commit()

    return FileResponse.from_orm(file, include_content=include_content)


@router.post("/{project_id}/files", response_model=FileResponse)
async def create_file(
        project_id: str,
        file_data: FileCreateRequest,
        current_user: User = Depends(require_auth),
        db: AsyncSession = Depends(get_db)
):
    """创建新文件 ✨"""

    await check_project_access(project_id, current_user, db, CollaboratorRole.DEVELOPER)

    # 清理文件名和路径
    file_name = sanitize_filename(file_data.name)
    file_path = sanitize_filename(file_data.path) if file_data.path else file_name

    # 验证文件类型
    if not validate_file_type(file_name, ALLOWED_EXTENSIONS):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="不支持的文件类型"
        )

    # 检查文件是否已存在
    result = await db.execute(
        select(File).where(
            File.project_id == project_id,
            File.path == file_path
        )
    )
    if result.scalar_one_or_none():
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="文件已存在"
        )

    # 计算文件信息
    content = file_data.content or ""
    file_extension = file_name.split('.')[-1].lower() if '.' in file_name else 'txt'

    # 创建文件
    new_file = File(
        name=file_name,
        path=file_path,
        content=content,
        project_id=project_id,
        file_type=file_extension,
        size=len(content.encode('utf-8')),
        lines=count_lines(content),
        checksum=calculate_file_checksum(content),
        is_binary=False,
        metadata=file_data.metadata or {}
    )

    db.add(new_file)
    await db.commit()
    await db.refresh(new_file)

    # 更新项目统计
    await _update_project_stats(project_id, db)

    logger.success(f"文件创建成功: {file_path} in project {project_id}")
    log_business_event("FILE_CREATED", user_id=current_user.id, project_id=project_id,
                       details={"file_id": new_file.id, "file_path": file_path})

    return FileResponse.from_orm(new_file)


@router.put("/{project_id}/files/{file_id}", response_model=FileResponse)
async def update_file(
        project_id: str,
        file_id: str,
        file_update: FileUpdateRequest,
        current_user: User = Depends(require_auth),
        db: AsyncSession = Depends(get_db)
):
    """更新文件 ✏️"""

    await check_project_access(project_id, current_user, db, CollaboratorRole.DEVELOPER)

    result = await db.execute(
        select(File).where(
            File.id == file_id,
            File.project_id == project_id
        )
    )
    file = result.scalar_one_or_none()

    if not file:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="文件不存在"
        )

    # 更新文件内容
    update_data = file_update.dict(exclude_unset=True)

    if 'content' in update_data:
        content = update_data['content']
        update_data['size'] = len(content.encode('utf-8'))
        update_data['lines'] = count_lines(content)
        update_data['checksum'] = calculate_file_checksum(content)
        update_data['version'] = file.version + 1

    # 应用更新
    for field, value in update_data.items():
        setattr(file, field, value)

    await db.commit()
    await db.refresh(file)

    # 更新项目统计
    await _update_project_stats(project_id, db)

    logger.success(f"文件更新成功: {file.path}")
    log_business_event("FILE_UPDATED", user_id=current_user.id, project_id=project_id,
                       details={"file_id": file_id})

    return FileResponse.from_orm(file)


@router.delete("/{project_id}/files/{file_id}")
async def delete_file(
        project_id: str,
        file_id: str,
        current_user: User = Depends(require_auth),
        db: AsyncSession = Depends(get_db)
):
    """删除文件 🗑️"""

    await check_project_access(project_id, current_user, db, CollaboratorRole.DEVELOPER)

    result = await db.execute(
        select(File).where(
            File.id == file_id,
            File.project_id == project_id
        )
    )
    file = result.scalar_one_or_none()

    if not file:
        raise HTTPException(
            status_code=status.HTTP_404_NOT_FOUND,
            detail="文件不存在"
        )

    file_path = file.path
    await db.delete(file)
    await db.commit()

    # 更新项目统计
    await _update_project_stats(project_id, db)

    logger.warning(f"文件删除: {file_path} from project {project_id}")
    log_business_event("FILE_DELETED", user_id=current_user.id, project_id=project_id,
                       details={"file_path": file_path})

    return {"message": "文件已删除"}


@router.post("/{project_id}/files/upload", response_model=FileUploadResponse)
async def upload_file(
        project_id: str,
        file: UploadFile = FastAPIFile(...),
        path: Optional[str] = None,
        current_user: User = Depends(require_auth),
        db: AsyncSession = Depends(get_db)
):
    """上传文件 📤"""

    await check_project_access(project_id, current_user, db, CollaboratorRole.DEVELOPER)

    # 验证文件大小
    if file.size and file.size > MAX_FILE_SIZE:
        raise HTTPException(
            status_code=status.HTTP_413_REQUEST_ENTITY_TOO_LARGE,
            detail=f"文件大小不能超过 {MAX_FILE_SIZE // (1024 * 1024)}MB"
        )

    # 清理文件名
    file_name = sanitize_filename(file.filename or "untitled")

    # 验证文件类型
    if not validate_file_type(file_name, ALLOWED_EXTENSIONS):
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="不支持的文件类型"
        )

    # 读取文件内容
    try:
        content_bytes = await file.read()
        content = content_bytes.decode('utf-8')
    except UnicodeDecodeError:
        raise HTTPException(
            status_code=status.HTTP_400_BAD_REQUEST,
            detail="文件编码不支持，请使用UTF-8编码"
        )

    # 设置文件路径
    file_path = f"{path}/{file_name}" if path else file_name
    file_path = sanitize_filename(file_path)

    # 检查文件是否已存在
    result = await db.execute(
        select(File).where(
            File.project_id == project_id,
            File.path == file_path
        )
    )
    existing_file = result.scalar_one_or_none()

    if existing_file:
        # 更新现有文件
        existing_file.content = content
        existing_file.size = len(content_bytes)
        existing_file.lines = count_lines(content)
        existing_file.checksum = calculate_file_checksum(content)
        existing_file.version += 1

        await db.commit()
        await db.refresh(existing_file)

        logger.success(f"文件更新成功: {file_path}")
        return FileUploadResponse(
            file_id=existing_file.id,
            message="文件更新成功",
            file_info=FileResponse.from_orm(existing_file, include_content=False)
        )
    else:
        # 创建新文件
        file_extension = file_name.split('.')[-1].lower() if '.' in file_name else 'txt'

        new_file = File(
            name=file_name,
            path=file_path,
            content=content,
            project_id=project_id,
            file_type=file_extension,
            size=len(content_bytes),
            lines=count_lines(content),
            checksum=calculate_file_checksum(content),
            is_binary=False
        )

        db.add(new_file)
        await db.commit()
        await db.refresh(new_file)

        logger.success(f"文件上传成功: {file_path}")
        return FileUploadResponse(
            file_id=new_file.id,
            message="文件上传成功",
            file_info=FileResponse.from_orm(new_file, include_content=False)
        )


async def _update_project_stats(project_id: str, db: AsyncSession):
    """更新项目统计信息"""
    from backend.models.project import Project

    # 计算文件统计
    result = await db.execute(
        select(
            func.count(File.id).label('file_count'),
            func.sum(File.lines).label('total_lines')
        ).where(File.project_id == project_id)
    )
    stats = result.first()

    # 更新项目统计
    project_result = await db.execute(
        select(Project).where(Project.id == project_id)
    )
    project = project_result.scalar_one_or_none()

    if project:
        project.file_count = stats.file_count or 0
        project.total_lines = stats.total_lines or 0
        await db.commit()
